//
//  mesh.cpp
//  RenderV1
//
//  Created by 黄翔 on 2019/9/9.
//  Copyright © 2019 黄翔. All rights reserved.
//

#include <glad/glad.h>
#include "render_v1.h"

using namespace hxe;
using namespace std;

Mesh::~Mesh()
{
    glDeleteBuffers(1, &ebo);
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArrays(1, &vao);

    delete this->vertices;
    delete this->normals;
    delete this->uv;
    delete this->indices;
}

Mesh::Mesh(vector<Vector3>* vertices, vector<unsigned int>* indices)
{
    this->vertices = vertices;
    this->indices = indices;
    
    setupMesh();
}


Mesh::Mesh(vector<Vector3>* vertices, vector<Vector3>* normals, vector<Vector2>* uv, vector<unsigned int>* indices)
{
    this->vertices = vertices;
    this->normals = normals;
    this->uv = uv;
    this->indices = indices;

    setupMesh();
}

hxe::Mesh::Mesh(vector<CombineInstance>& combines)
{
    this->vertices = new vector<Vector3>();
    this->normals = new vector<Vector3>();
    this->uv = new vector<Vector2>();
    this->indices = new vector<unsigned int>();

    int indexOffset = 0;
    for (unsigned int i = 0; i < combines.size(); i++)
    {
        Matrix4x4 transform = combines[i].transform;
        Mesh* mesh = combines[i].mesh;
        for (unsigned int j = 0; j < mesh->vertices->size(); j++)
        {
            this->vertices->push_back(transform *  Vector4((*mesh->vertices)[j], 1.0f));
        }

        this->normals->insert(this->normals->end(), mesh->normals->begin(), mesh->normals->end());
        this->uv->insert(this->uv->end(), mesh->uv->begin(), mesh->uv->end());

        for (unsigned int j = 0; j < mesh->indices->size(); j++)
        {
            this->indices->push_back((*mesh->indices)[j] + indexOffset);
        }

        indexOffset += mesh->vertices->size();
    }

    setupMesh();
}

void Mesh::setupMesh()
{
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    unsigned int sizeVertices = (unsigned int) vertices->size() * sizeof(Vector3);
    unsigned int sizeNormals = (unsigned int)normals->size() * sizeof(Vector3);
    unsigned int sizeUv = (unsigned int)uv->size() * sizeof(Vector2);
    glBufferData(GL_ARRAY_BUFFER, sizeVertices + sizeNormals + sizeUv, NULL, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeVertices, &(*vertices)[0]);
    glBufferSubData(GL_ARRAY_BUFFER, sizeVertices, sizeNormals, &(*normals)[0]);
    glBufferSubData(GL_ARRAY_BUFFER, sizeVertices + sizeNormals, sizeUv, &(*uv)[0]);
    
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), (void*)(long)sizeVertices);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), (void*)((long)sizeVertices + sizeNormals));
    glEnableVertexAttribArray(2);
    
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices->size() * sizeof(unsigned int), &(*indices)[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

